import { ParticleAsset, ParticleSystem2D, Sprite, resources, SpriteFrame, isValid, sp, Prefab, instantiate, Node, AssetManager, ImageAsset, Texture2D } from "cc";
import { GameManager, regGameManager } from "../GameManager";
import { LoggerManager } from "./LoggerManager";
/**用来计数设置Sprf的请求顺序，防止后面发出的请求覆盖前面的请求 */
export interface AssetSetCounter {
    /**设置次数 */
    assetSetCount: number;
}

export class RemoteBundleConfig {
    constructor(
        public name: string,
        public url: string
    ) { }
}

/**资源管理器 */
@regGameManager()
export class AssetsManager extends GameManager {

    remoteBundleConfigs: RemoteBundleConfig[] = [];

    /**加载并设置图片 */
    setSprframe(spr: Sprite, path: string, bundleName: string = "resources", sprfSetCounter: AssetSetCounter = null): Promise<SpriteFrame> {
        if (sprfSetCounter) {
            sprfSetCounter.assetSetCount++;
        }
        const setCount = sprfSetCounter ? sprfSetCounter.assetSetCount : 0;

        return new Promise(async (resolve) => {
            const bundle = bundleName ? await this.getBundle(bundleName) : resources;

            bundle.load(`${path}${'/spriteFrame'}`, SpriteFrame, (err, sprf: SpriteFrame) => {
                if (sprfSetCounter && setCount != sprfSetCounter.assetSetCount) {
                    resolve(sprf);
                    return;
                }
                if (err) {
                    LoggerManager.instance().error(path, err);
                    resolve(null);
                    return;
                }


                if (!spr?.node || !isValid(spr.node, true)) {
                    resolve(sprf);
                    return;
                }
                spr.spriteFrame = sprf;
                resolve(sprf);
            });
        });

    }

    /**加载并设置粒子 */
    setPlist(plistSystem: ParticleSystem2D, path: string, bundleName: string = "resources", assetSetCounter: AssetSetCounter = null): Promise<ParticleAsset> {
        if (assetSetCounter) {
            assetSetCounter.assetSetCount++;
        }
        const setCount = assetSetCounter ? assetSetCounter.assetSetCount : 0;

        return new Promise(async (resolve) => {
            const bundle = bundleName ? await this.getBundle(bundleName) : resources;

            bundle.load(`${path}`, ParticleAsset, (err, asset: ParticleAsset) => {
                if (assetSetCounter && setCount != assetSetCounter.assetSetCount) {
                    resolve(asset);
                    return;
                }
                if (err) {
                    LoggerManager.instance().error(path, err);
                    resolve(null);
                    return;
                }


                if (!plistSystem.node || !isValid(plistSystem.node, true)) {
                    resolve(asset);
                    return;
                }
                plistSystem.file = asset;
                resolve(asset);
            });
        });

    }

    /**远程加载并设置图片 */
    setSprframeByRemote(spr: Sprite, path: string, sprfSetCounter: AssetSetCounter = null): Promise<SpriteFrame> {

        const setCount = sprfSetCounter ? sprfSetCounter.assetSetCount : 0;
        return new Promise((resolve) => {
            if (!path) {
                resolve(null);
                return;
            }
            path = path.replace(/^http:/, 'https:');
            AssetManager.instance.loadRemote<ImageAsset>(path, { ext: '.png' }, (err, asset) => {
                if (err) {
                    LoggerManager.instance().error(path, err);
                    resolve(null);
                    return;
                }
                // console.log("------",asset);

                const texture = new Texture2D();
                texture.image = asset;


                const sprf = new SpriteFrame();
                sprf.texture = texture;
                if (!spr.node || !isValid(spr.node, true)) {
                    resolve(sprf);
                    return;
                }
                spr.spriteFrame = sprf;
                resolve(sprf);
            });
        });
    }

    /**加载并设置spine动画 */
    setSpineSke(ske: sp.Skeleton, path: string, bundleName: string = "resources") {

        return new Promise<sp.SkeletonData>(async (resolve) => {
            const bundle = bundleName ? await this.getBundle(bundleName) : resources;

            bundle.load(`${path}`, sp.SkeletonData, (err, data: sp.SkeletonData) => {
                if (err) {
                    LoggerManager.instance().error(path, err);
                    resolve(null);
                    return;
                }
                if (!ske.node || !isValid(ske.node, true)) {
                    resolve(data);
                    return;
                }
                ske.skeletonData = data;
                resolve(data);
            });
        });
    }

    /**动态加载预制体并创建实例 */
    inistaniateByPath(path: string, bundleName: string = "resources", cbk?: (p: Prefab) => void) {

        return new Promise<Node>(async (resolve, reject) => {
            const bundle = bundleName ? await this.getBundle(bundleName) : resources;

            bundle.load(path, Prefab, (err, prefab: Prefab) => {
                if (err) {
                    LoggerManager.instance().log(err);
                    resolve(null);
                    return;
                }
                cbk && cbk(prefab);
                const node = instantiate(prefab);
                resolve(node);
            });
        });
    }


    /**
 * 预加载bundle内的预置体
 * @param path 
 * @param bundleName 
 */
    async preloadPrefabByBundle(path: string, bundleName = "resources") {
        const bundle = await this.getBundle(bundleName);
        return new Promise<void>((resolve, reject) => {
            if (bundle) {
                bundle.preload(path, (err,data) => {
                   
                    resolve();
                });
            } else {
                resolve();
            }
        })

    }


    /**
  * 加载bundle指定路径内的预置体
  * @param path 
  * @param bundleName 
  */
    loadPrefabsByFromDir(dirPath: string, bundleName = "resources") {
        return new Promise<Prefab[]>(async (r, j) => {
            const bundle: AssetManager.Bundle = await this.getBundle(bundleName);


            if (bundle) {
                bundle.loadDir(dirPath, Prefab, (err, datas: Prefab[]) => {
                    if (err) {
                        r([]);
                        return;
                    }
                    r(datas);
                });

            } else {
                r([]);
            }
        });

    }

    /**
* 加载bundle指定路径内的预置体
* @param path 
* @param bundleName 
*/
    loadPrefab(path: string, bundleName = "resources") {
        return new Promise<Prefab>(async (r, j) => {
            const bundle: AssetManager.Bundle = await this.getBundle(bundleName);


            if (bundle) {
                bundle.load(path, Prefab, (err, data: Prefab) => {
                    if (err) {
                        r(null);
                        return;
                    }
                    r(data);
                });

            } else {
                r(null);
            }
        });

    }

    getBundle(bundleName: string) {
        return new Promise<AssetManager.Bundle>((r, j) => {
            const bundle = AssetManager.instance.getBundle(bundleName);


            if (bundle) {
                r(bundle);
            } else {
                const cdnHost = window["cdn_host"];
                if (cdnHost) {//饿了么等平台上加载bundle的方式
                    const url = (cdnHost ? cdnHost + "remote/" : "") + bundleName;
                    AssetManager.instance.loadBundle(url, (err: Error, bundle: AssetManager.Bundle) => {
                        if (err) {
                            LoggerManager.instance().log(err);
                            r(null);
                        } else {
                            r(bundle);
                        }
                    });
                } else {


                    const config = this.remoteBundleConfigs.find(i => i.name == bundleName);
                    console.log("zzzzzzz loadBundle", bundleName, config);

                    if (config) {//配置了远程包地址
                        AssetManager.instance.loadBundle(config.url, (err, data) => {
                            if (err) {
                                r(null);
                            } else {
                                r(data);
                            }
                        });
                    } else {
                        AssetManager.instance.loadBundle(bundleName, (err, data) => {
                            if (err) {
                                r(null);
                            } else {
                                r(data);
                            }
                        });
                    }
                }
            }

        });
    }

    async clearBundle(bundleName: string) {
        let bundle: AssetManager.Bundle = null;
        bundle = await this.getBundle("subBundle");
        if (bundle) {
            /** bundle 脚本表 */
            const bundle_script_tab: Record<string, any> = {};
            /** js 系统 */
            const system_js = window["System"];
            /** 脚本缓存表 */
            const script_cache_tab: Record<string, any> = system_js[Reflect.ownKeys(system_js).find((v) => typeof v === "symbol")!];

            // 更新 bundle 信息
            // this.set(bundle_);

            // 初始化 bundle 脚本表
            Object.keys(script_cache_tab).forEach((v_s) => {
                const current = script_cache_tab[v_s] as { d: any[]; id: string; };
                const parent = script_cache_tab[v_s].p;

                if (!parent?.d || current.id !== parent.id) {
                    return;
                }

                const name_s = parent.id.slice((parent.id as string).lastIndexOf("/") + 1);

                bundle_script_tab[name_s] = parent;
            });

            // 清理脚本缓存
            {
                const bundle_root = bundle_script_tab[bundleName]?.d[0];

                if (bundle_root) {
                    bundle_root.d.forEach((v: { id: string; }) => {
                        system_js.delete(v.id);
                    });

                    system_js.delete(bundle_root.id);
                    system_js.delete(bundle_root.p.id);
                }
            }

            bundle.releaseAll();
            AssetManager.instance.removeBundle(bundle);
        }

    }
    loadRemoteBundle(bundleName: string, baseUrl: string) {
        return new Promise<AssetManager.Bundle>((r, j) => {
            const bundle = bundleName ? AssetManager.instance.getBundle(bundleName) : resources;
            if (bundle) {
                r(bundle);
            } else {
                const url = baseUrl + bundleName;
                AssetManager.instance.loadBundle(url, (err: Error, bundle: AssetManager.Bundle) => {
                    if (err) {
                        LoggerManager.instance().log(err);
                        j(err);
                    } else {
                        r(bundle);
                    }
                });
            }

        });
    }
}